/*
* Copyright (C) 2019 ~ 2022 Uniontech Software Technology Co.,Ltd.
*
* Author:     yanghongwei <yanghongwei@uniontech.com>
*
* Maintainer: yanghongwei <yanghongwei@uniontech.com>
*/

#ifndef INOTIFY_H
#define INOTIFY_H

#include "abstractnotify.h"

#include <map>
#include <atomic>

/**
 * @brief inotify的具体实现
 */
// TODO: 目前多个process同时添加移除相似或父子目录存在问题，且监控目录下的子目录还未加入监控，后续优化，逐步完善
/**
 * 1.子目录监控添加，但是目前多个process对同一目录或父子目录的监听不同事件类型处理还存在问题
 */
class INotify : public AbstractNotify
{
public:
    INotify();
    ~INotify() override;

    bool init() override; // inotify的初始化
    bool addNode(const NotifyNode &node) override; // 添加一个要监听的节点
    bool removeNode(const NotifyNode &node) override; // 移除一个已经监听的节点
    bool start() override; // 启动监听线程
    bool stop() override; // 停止监听线程
    void run() override; // 线程执行体
    bool isRunning() override; // 线程是否在运行

private:
    uint32_t getINotifyEvents(const NotifyNode &node); // FileEvent转换为inotify event
    uint32_t getFileNotifyEvents(const uint32_t &events); // inotify event转换为FileEvent
    void handleEvent(char *buff, int len); // 事件处理
    bool addPath(const std::string &path, uint32_t events = 0); // 添加某个路径的监听
    void removePath(const std::string &path); // 移除某个路径的监听
    bool isCanRemove(const std::string &path); // 判断一个路径是否可以移除
    uint32_t getWatchEvents(const std::string &path); // 获取路径监听的事件类型

private:
    std::atomic<bool> m_running; // 线程运行状态
    int m_fd; // inotify初始化句柄
    std::map<int, int> m_mapListenWdChildren; // 监测目录绑定wd对应子目录，之后应该要用到
    std::map<int, std::string> m_mapListenWdPath; // 监测目录绑定wd
    std::map<std::string, int> m_mapListenPathWd; // 监测目录绑定wd
    std::map<NotifyNode, int> m_mapNotifyNode; // 保存监听的节点
};

#endif //INOTIFY_H
